/****************************************************************************** * Copyright (c) 2004, 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation ****************************************************************************/ package org.eclipse.gmf.runtime.emf.core.internal.util; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.util.ResourceLocator; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EEnum; import org.eclipse.emf.ecore.EEnumLiteral; import org.eclipse.emf.ecore.ENamedElement; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EParameter; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.provider.IItemLabelProvider; import org.eclipse.gmf.runtime.common.core.util.Trace; import org.eclipse.gmf.runtime.emf.core.internal.plugin.EMFCoreDebugOptions; import org.eclipse.gmf.runtime.emf.core.internal.plugin.EMFCorePlugin; /** * This class manages meta-models and provide localization of meta-class names. * * @author rafikj * @author Christian W. Damus (cdamus) */ public class MetamodelManager { // used to get resource locators when none are provided to us private static final ComposedAdapterFactory adapterFactory = new ComposedAdapterFactory( ComposedAdapterFactory.Descriptor.Registry.INSTANCE); private final static Map METAMODEL_MAP = new HashMap(); private final static Map REVERSE_METAMODEL_MAP = new HashMap(); /** * Register meta-model object. */ public static void register(ENamedElement element) { register(element, null); } /** * Register meta-model object. */ public static void register(ENamedElement element, ResourceLocator resourceLocator) { if (element instanceof EOperation) return; if (element instanceof EParameter) return; String id = getNonCachedID(element); String name = element.getName(); String displayName = null; if ((resourceLocator == null) && (element instanceof EPackage)) { // get a resource locator from the adapter factory registered // against the IItemLabelProvider adapter type resourceLocator = findResourceLocator((EPackage) element); } if (resourceLocator != null) { if (element instanceof EClass) { displayName = resourceLocator.getString("_UI_" + name //$NON-NLS-1$ + "_type"); //$NON-NLS-1$ } else if (element instanceof EStructuralFeature) { EClass eClass = ((EStructuralFeature) element) .getEContainingClass(); if (eClass != null) displayName = resourceLocator.getString("_UI_" //$NON-NLS-1$ + eClass.getName() + "_" + name + "_feature"); //$NON-NLS-1$//$NON-NLS-2$ } else if (element instanceof EEnumLiteral) { EEnum eEnum = ((EEnumLiteral) element).getEEnum(); if (eEnum != null) displayName = resourceLocator.getString("_UI_" //$NON-NLS-1$ + eEnum.getName() + "_" + name + "_literal"); //$NON-NLS-1$//$NON-NLS-2$ } } if (displayName == null) displayName = name; METAMODEL_MAP.put(element, new MetaModelDescriptor(id, displayName)); REVERSE_METAMODEL_MAP.put(id, element); for (Iterator i = element.eContents().iterator(); i.hasNext();) { Object child = i.next(); if (child instanceof ENamedElement) register((ENamedElement) child, resourceLocator); } } /** * Attempts to find a resource locator for the specified metamodel package, * using a heuristic that assumes that item-provider adapters implement * the ResourceLocator interface (which is the default code generation). * * @param pkg a package for which we need a resource locator * * @return the resource locator if we could find one; <code>null</code> otherwise */ private static ResourceLocator findResourceLocator(EPackage pkg) { ResourceLocator result = null; // the compased adapter factory has a registry of pairs by EPackage // and adapter class List types = new java.util.ArrayList(2); types.add(pkg); types.add(IItemLabelProvider.class); AdapterFactory factory = adapterFactory.getFactoryForTypes(types); if (factory != null) { // find some EClass to instantiate to get an item provider for it EObject instance = null; for (Iterator iter = pkg.getEClassifiers().iterator(); iter.hasNext();) { Object next = iter.next(); if ((next instanceof EClass) && !((EClass) next).isAbstract()) { instance = pkg.getEFactoryInstance().create((EClass) next); break; } } if (instance != null) { Object adapter = factory.adapt(instance, IItemLabelProvider.class); if (adapter instanceof ResourceLocator) { result = (ResourceLocator) adapter; } } } return result; } /** * Get the ID of a meta-model object. */ public static String getID(ENamedElement element) { if (element instanceof EOperation) { RuntimeException e = new IllegalArgumentException( "EOperation does not support IDs"); //$NON-NLS-1$ Trace.throwing(EMFCorePlugin.getDefault(), EMFCoreDebugOptions.EXCEPTIONS_THROWING, MetamodelManager.class, "getID", e); //$NON-NLS-1$ throw e; } if (element instanceof EParameter) { RuntimeException e = new IllegalArgumentException( "EParameter does not support IDs"); //$NON-NLS-1$ Trace.throwing(EMFCorePlugin.getDefault(), EMFCoreDebugOptions.EXCEPTIONS_THROWING, MetamodelManager.class, "getID", e); //$NON-NLS-1$ throw e; } MetaModelDescriptor descriptor = (MetaModelDescriptor) METAMODEL_MAP .get(element); if (descriptor != null) return descriptor.id; return getNonCachedID(element); } /** * Get the localized name of a meta-model object. Name does not contain * spaces. */ public static String getLocalName(ENamedElement element) { tryRegisterElement(element); MetaModelDescriptor descriptor = (MetaModelDescriptor) METAMODEL_MAP .get(element); if (descriptor != null) return descriptor.localName; return element.getName(); } /** * Get the localized name of a meta-model object. Name may contain spaces. */ public static String getDisplayName(ENamedElement element) { tryRegisterElement(element); MetaModelDescriptor descriptor = (MetaModelDescriptor) METAMODEL_MAP .get(element); if (descriptor != null) return descriptor.displayName; return element.getName(); } /** * Find meta-model object given its ID. */ public static ENamedElement getElement(String id) { ENamedElement result = (ENamedElement) REVERSE_METAMODEL_MAP.get(id); if ((result == null) && (id != null)) { // not registered, yet. Look it up in the registry result = findInPackageRegistry(id); } return result; } /** * Find the specified named element by ID in the global package registry. * <b>Side-effect:</b> registers the package when found so that we don't * need to do this again. * * @param id the ID to find. Must not be <code>null</code> * @return the named element, or <code>null</code> if not found */ private static ENamedElement findInPackageRegistry(String id) { ENamedElement result = null; int dot = id.indexOf('.'); String pkgName = (dot >= 0)? id.substring(0, dot) : id; for (Iterator iter = EPackage.Registry.INSTANCE.values().iterator(); iter.hasNext();) { Object next = iter.next(); if (next instanceof EPackage) { // skip descriptors because if the EPackage hasn't been // instantiated then it cannot be in use by the client EPackage pkg = (EPackage) next; if (pkgName.equals(pkg.getName())) { result = findElement(pkg, id); if (result != null) { // register the package for subsequent look-ups register(pkg, null); break; } } } } return result; } private static ENamedElement findElement(ENamedElement element, String id) { ENamedElement result = null; int dot = id.indexOf('.'); if (dot < 0) { if (id.equals(element.getName())) { // got the final result result = element; } // else the element is not found here } else { String name = id.substring(0, dot); if (name.equals(element.getName())) { // search recursively in the sub-tree id = id.substring(dot + 1); for (Iterator iter = element.eContents().iterator(); (result == null) && iter.hasNext();) { Object next = iter.next(); if (next instanceof ENamedElement) { result = findElement((ENamedElement) next, id); } } } } return result; } /** * Get the non-cached ID of a meta-model object. */ private static String getNonCachedID(ENamedElement element) { StringBuffer id = new StringBuffer(); ENamedElement current = element; while (current != null) { id.insert(0, current.getName()); EObject container = current.eContainer(); current = null; if (container != null) { if ((container instanceof ENamedElement)) { current = (ENamedElement) container; id.insert(0, '.'); } else { // ENamedElements not contained by named elements (e.g., // contained in annotations) are not supported return null; } } } return id.toString(); } /** * This class describes a meta-model object. */ private static class MetaModelDescriptor { public String id = null; public String localName = null; public String displayName = null; public MetaModelDescriptor(String id, String displayName) { super(); this.id = id.intern(); this.localName = displayName.replaceAll(" ", "").intern(); //$NON-NLS-1$//$NON-NLS-2$ this.displayName = displayName.intern(); } } /** * Registers the package an element belongs to. All elements of the package * are registered with the package * * @param element An element that will be tried to get registered */ private static void tryRegisterElement(ENamedElement element) { // EOperation and EParameter can't have ids and hence cannot be registered if (element instanceof EOperation || element instanceof EParameter) return; String id = getID(element); if (id == null) return; int dot = id.indexOf('.'); // It is assumed that package names are equal to their IDs String pkgName = (dot >= 0)? id.substring(0, dot) : id; // If package is registered than no need to register it again if (REVERSE_METAMODEL_MAP.get(pkgName)!=null) return; for (Iterator iter = EPackage.Registry.INSTANCE.values().iterator(); iter.hasNext();) { Object next = iter.next(); if (next instanceof EPackage) { // skip descriptors because if the EPackage hasn't been // instantiated then it cannot be in use by the client EPackage pkg = (EPackage) next; if (pkgName.equals(pkg.getName())) { register(pkg, null); } } } } }